﻿--[[
	Widget name	  	PropertyList
	Author     	 	Kurapica
--]]
     
-- PropertyList
do    
    local getmetatable = getmetatable
    local pairs = pairs
    local ipairs = ipairs
    local type = type
    local error = error
    local floor = floor
	local tostring = tostring
	local random = random
	local tinsert = table.insert
	local tremove = table.remove
	local wipe = table.wipe
    local CreateFrame = IGAS.GUI.CreateFrame
    
	local _WidgetName = "PropertyList"
	local _Base = IGAS.GUI.Widget.Frame

    local _Widget = IGAS.Studio.Widget
    local _PropertyType = IGAS.GUI.Base.PropertyType
	
    ------------------------------------------------------
	---------------------   PropertyList   -------------------
	------------------------------------------------------
	local _WidgetName = "PropertyList"
    local _Base = "Frame"
	
	local _PropertyList

    -- Scripts
	local _FrameBackdrop = {
        bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        tile = true, tileSize = 16, edgeSize = 16,
        insets = { left = 3, right = 3, top = 3, bottom = 3 }
	}
	
	local _SelFrame
	local _ObjectType
	
	-- Frame
	local function OnMouseDown(self)
		self:StartMoving()
	end

	local function OnMouseUp(self)
		self:StopMovingOrSizing()
	end
	
	-- Sizer-SouthEast	
	local function sizerseOnMouseDown(self)
		if self:GetParent().Resizable then
			self:GetParent():StartSizing("BOTTOMRIGHT")
		end
	end
	
	local function sizerOnMouseUp(self)
		self:GetParent():StopMovingOrSizing()
	end
	
	-- Chooser
	local level = 0
	local orderT = {}
	
	local nodeHeight = 26
	local nodeIndent = 10
	
	local function FixHeightSeparator(self)
		local height = nodeHeight

		if self:GetChild("PropertySet1") then
			if self.__NodeNum > 0 then
				for i = 1, self.__NodeNum do
					if self:GetChild("PropertySet"..i) and self:GetChild("PropertySet"..i).Visible then
						height = height + self:GetChild("PropertySet"..i).Height
					end
				end
			end
		end

		self.Height = height
	end
	
	local function FixHeightList(self)
		local height = 0

		if self:GetChild("PropertySeparator1") then
			if self.__NodeNum > 0 then
				for i = 1, self.__NodeNum do
					if self:GetChild("PropertySeparator"..i) and self:GetChild("PropertySeparator"..i).Visible then
						height = height + self:GetChild("PropertySeparator"..i).Height
					end
				end
			end
		end

		self.Height = height
	end
	
	-- PropertySet's Scripts
	local function PropertySet_OnPropertyChanged(self, object, prop, value)
		_PropertyList:Fire("OnPropertyChanged", object, prop, value)
	end
	
	-- Refresh List
	local function RefreshList(container, objectType)
		local propertySpt
		local propertySet
		local property
		local propertyName
		
		local index = 0
		
		if objectType.Base then
			RefreshList(container, objectType.Base)
		end
				
		level = level + 1
		propertySpt = CreateFrame(_Widget.PropertySeparator, "PropertySeparator"..level, container)
		propertySpt.Visible = true
		propertySpt.ToggleState = true
		propertySpt.Text = objectType.Name
		
		for propertyName, property in pairs(objectType.Property) do
			if not orderT[propertyName] then
				orderT[propertyName] = true
				
				if property["Get"] and property["Set"] and property["Type"] and 
					(property["Type"]["Type"] == "number" or property["Type"]["Type"] == "string" or 
					property["Type"]["Type"] == "boolean" or property["Type"]["Type"] == "enum") then
					-- Can be list in the propertyList
					index = index + 1
					propertySet = CreateFrame(_Widget.PropertySet, "PropertySet"..index, propertySpt)
					propertySet.Visible = true
					
					propertySet:SetProperty(_SelFrame, propertyName)
					
					propertySet.OnPropertyChanged = PropertySet_OnPropertyChanged
				end
			end
		end
		
		-- Hide useless propertySet
		index = index + 1
		while propertySpt:GetChild("PropertySet"..index) do
			propertySpt:GetChild("PropertySet"..index):SetProperty(nil, nil)
			propertySpt:GetChild("PropertySet"..index).Visible = false
			index = index + 1
		end
		
		FixHeightSeparator(propertySpt)
	end
	
	local function Chooser_OnValueChanged(self, value)
		local container = self.Parent.Container
				
		_SelFrame = value
		
		if value and value:IsObjectType(_Widget.ShadowFrame) then
			_SelFrame = frame.TrueFrame			
		end
		
		if _SelFrame then
			self.Parent:GetChild("Delete").Enabled = true
			if IGAS.Studio.Advance[_SelFrame:GetObjectType()] then
				self.Parent:GetChild("Advance").Enabled = true
			else
				self.Parent:GetChild("Advance").Enabled = false
			end
		else
			self.Parent:GetChild("Delete").Enabled = false
			self.Parent:GetChild("Advance").Enabled = false
		end
		
		-- Init
		level = 0
		wipe(orderT)
		self.Parent:GetChild("ScrollForm").Value = 0
		
		-- Refresh
		if _SelFrame then
			RefreshList(container, _SelFrame:GetObjectType())
		end
		
		-- Hide useless propertySet
		if container.__NodeNum > level then
			local index = container.__NodeNum
			
			while index > level do
				container:GetChild("PropertySeparator"..index).ToggleState = false
				container:GetChild("PropertySeparator"..index).Visible = false
				index = index - 1
			end
		end
		
		FixHeightList(container)
	end
	
	-- Advance settings for item
	local function Advance_OnClick(self, button)
		if _SelFrame and IGAS.Studio.Advance[_SelFrame:GetObjectType()] and IGAS.Studio.Advance[_SelFrame:GetObjectType()]["SetFrame"] then
			IGAS.Studio.Advance[_SelFrame:GetObjectType()]:SetFrame(_SelFrame)
			IGAS.Studio.Advance[_SelFrame:GetObjectType()]:Show()
		end
	end
	
	-- Delete Item
	local function Dispose(self, frame)
		-- Remove Child
		for f in pairs(self.__FrameList) do
			if f.Parent == frame then
				Dispose(self, f)
			end
		end
		
		frame.__InDesignMode = nil
		self:RemoveFrame(frame)
		self.Parent:Fire("OnFrameDispose", frame)
		frame:Dispose()
	end
	
	local function Delete_OnClick(self, button)
		local frame = self.Parent.SelectedFrame
		if frame then
			Dispose(self.Parent, frame)
		end
	end
	
	-- ScriptType
	local _ScriptType = {
		["OnAdvance"] = true,
		["OnPropertyChanged"] = true,
		["OnFrameDispose"] = true,
	}
	
	-- FuncProxy
	local _FuncProxy = {
		["AddFrame"] = function(self, frame)
			self.Chooser:AddItem(frame, frame.Name)
			self.__FrameList[frame] = true
		end,
		["RemoveFrame"] = function(self, frame)
			self.Chooser:RemoveItem(frame)
			self.__FrameList[frame] = nil
		end,
    }
    
	-- Property
	local _Property = {
		-- SelectedFrame
		["SelectedFrame"] = {
			["Set"] = function(self, frame)
				self:GetChild("Chooser").Value = frame
			end,
			
			["Get"] = function(self)
				if _SelFrame and _SelFrame.Parent and _SelFrame.Parent:IsObjectType(_Widget.ShadowFrame) then
					return _SelFrame.Parent
				else
					return _SelFrame
				end
			end,
            
			["Type"] = _PropertyType.Object,
		},
		-- Container
        ["Container"] = {
			["Get"] = function(self)
				return self:GetChild("ScrollForm").Container
			end,
			
			["Type"] = _PropertyType.Object,
        },
    }
    
    -- New    
    local _New = function(parent)
        local frame = CreateFrame(_Base, nil, parent)
		
		-- So, we only need one.
		if _PropertyList then
			return _PropertyList
		end
		
		frame.__FrameList = {}
		
		frame.Width =200
		frame.Height = 400
		
		frame.Movable = true
		frame.Resizable = true
		frame.FrameStrata = "DIALOG"
		frame.Toplevel = true
		frame.MouseEnabled = true
		frame.MouseWheelEnabled = true
		frame.OnMouseDown = OnMouseDown
		frame.OnMouseUp = OnMouseUp
		
		frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", 0, 10)
		frame:SetBackdrop(_FrameBackdrop)
		frame:SetBackdropColor(0,0,0,1)
		frame:SetMinResize(200,200)
		frame:SetMaxResize(600,1000)
        		
		local sizer_se = CreateFrame("Frame","Sizer_se",frame)
		sizer_se.Width = 10
		sizer_se.Height = 10
		sizer_se.MouseEnabled = true
		sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
		sizer_se.OnMouseDown = sizerseOnMouseDown
		sizer_se.OnMouseUp = sizerOnMouseUp
		
		local chooser = CreateFrame("ComboBox", "Chooser", frame)
		chooser:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -10)
		chooser:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -6, -10)
		chooser.Editable = false
		
		local btnAdvance = CreateFrame("Button", "Advance", frame)
		btnAdvance:SetPoint("TOPLEFT", chooser, "BOTTOMLEFT", 0, -4)
		btnAdvance:SetPoint("TOPRIGHT", chooser, "BOTTOMRIGHT", 0, -4)
		btnAdvance.Height = 26
		btnAdvance.Style = "NORMAL"
		btnAdvance.Enabled = false
		btnAdvance.Text = "Advance"
		
		local btnDelete = CreateFrame("Button", "Delete", frame)
		btnDelete:SetPoint("TOPLEFT", btnAdvance, "BOTTOMLEFT", 0, -4)
		btnDelete:SetPoint("TOPRIGHT", btnAdvance, "BOTTOMRIGHT", 0, -4)
		btnDelete.Height = 26
		btnDelete.Style = "NORMAL"
		btnDelete.Enabled = false
		btnDelete.Text = "Delete"
				
		local scrollForm = CreateFrame("ScrollForm", "ScrollForm", frame)
		scrollForm:SetPoint("TOPLEFT", btnDelete, "BOTTOMLEFT", 0, -4)
		scrollForm:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 10)
		scrollForm:SetBackdrop(nil)
		scrollForm.ValueStep = 26
		scrollForm.Container.Height = 26
		
		chooser.OnValueChanged = Chooser_OnValueChanged
		btnAdvance.OnClick = Advance_OnClick
		btnDelete.OnClick = Delete_OnClick
		
		_PropertyList = frame
		
        return frame
    end
	
    local _WidgetInfo = {
        ["WidgetName"] = _WidgetName,
        ["Base"] = _Base,
        ["FuncProxy"] = _FuncProxy,
        ["Property"] = _Property,
        ["ScriptType"] = _ScriptType,
        ["New"] = _New,
    }
    
    _Widget[_WidgetName] = IGAS:NewWidget(_WidgetInfo)    
end